#include "background_task.h"

#include <esp_log.h>
#include <esp_task_wdt.h>

#define TAG "BackgroundTask"

/**
 * @brief 构造函数，创建后台任务线程
 * @param stack_size 线程栈大小，默认为8192字节
 */
BackgroundTask::BackgroundTask(uint32_t stack_size) {
    xTaskCreate([](void* arg) {
        BackgroundTask* task = (BackgroundTask*)arg;
        task->BackgroundTaskLoop();
    }, "background_task", stack_size, this, 2, &background_task_handle_);
}

/**
 * @brief 析构函数，清理后台任务线程资源
 */
BackgroundTask::~BackgroundTask() {
    if (background_task_handle_ != nullptr) {
        vTaskDelete(background_task_handle_);
    }
}

/**
 * @brief 安排一个回调函数在后台线程中执行
 * @param callback 要执行的回调函数
 */
void BackgroundTask::Schedule(std::function<void()> callback) {
    std::lock_guard<std::mutex> lock(mutex_);
    // 检查活跃任务数量，防止任务过多导致内存不足
    if (active_tasks_ >= 30) {
        int free_sram = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
        if (free_sram < 10000) {
            ESP_LOGW(TAG, "active_tasks_ == %u, free_sram == %u", active_tasks_.load(), free_sram);
        }
    }
    active_tasks_++;
    // 将回调函数包装后添加到任务队列
    main_tasks_.emplace_back([this, cb = std::move(callback)]() {
        cb();
        {
            std::lock_guard<std::mutex> lock(mutex_);
            active_tasks_--;
            // 如果所有任务都已完成，通知等待的线程
            if (main_tasks_.empty() && active_tasks_ == 0) {
                condition_variable_.notify_all();
            }
        }
    });
    // 通知后台线程有新任务
    condition_variable_.notify_all();
}

/**
 * @brief 等待所有已安排的任务完成
 * 此方法会阻塞调用线程，直到所有任务执行完毕
 */
void BackgroundTask::WaitForCompletion() {
    std::unique_lock<std::mutex> lock(mutex_);
    // 等待直到任务队列为空且没有活跃任务
    condition_variable_.wait(lock, [this]() {
        return main_tasks_.empty() && active_tasks_ == 0;
    });
}

/**
 * @brief 后台任务线程的主循环
 * 不断从任务队列中取出任务并执行
 */
void BackgroundTask::BackgroundTaskLoop() {
    ESP_LOGI(TAG, "background_task started");
    while (true) {
        std::unique_lock<std::mutex> lock(mutex_);
        // 等待直到有任务可执行
        condition_variable_.wait(lock, [this]() { return !main_tasks_.empty(); });
        
        // 移动任务队列到本地变量，避免长时间持有锁
        std::list<std::function<void()>> tasks = std::move(main_tasks_);
        lock.unlock();

        // 执行所有任务
        for (auto& task : tasks) {
            task();
        }
    }
}
